/********************************************************************
文件名称:   rngLib.c

文件功能:   环形数组库

文件说明:   该函数库从VxWorks rngLib.c下移植,当在单片机下使用时可能会申请失败
            可以通过在单片机启动汇编文件中修改堆大小解决。

当前版本:   V1.0

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
#include "stdlib.h"
#include "string.h"
#include "stdlib.h"
#include "rngLib.h"

/********************************************************************
函数名称:   rngCreate

函数功能:   rngCreate - create an empty ring buffer

参数名称        类型            输入/输出           含义
nbytes          size_t          input               number of bytes in ring buffer

返回值  :   The ID of the ring buffer, or NULL if memory cannot be allocated.

函数说明:   This routine creates a ring buffer of size <nbytes>, and initializes
            it.  Memory for the buffer is allocated from the system memory parti
            tion.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
RING_ID rngCreate
(
    size_t nbytes          /* number of bytes in ring buffer */
)
{
    char *buffer;

    RING_ID ringId = (RING_ID) malloc (sizeof (RING));

    if (ringId == NULL)
        return (NULL);

    /*
     * bump number of bytes requested because ring buffer algorithm
     * always leaves at least one empty byte in buffer
     */

    buffer = (char *) malloc (++nbytes);

    if (buffer == NULL)
    {
        free ((char *)ringId);
        return (NULL);
    }

    ringId->bufSize = nbytes;
    ringId->buf     = buffer;

    rngFlush (ringId);

    return (ringId);
}

/********************************************************************
函数名称:   rngDelete

函数功能:   rngDelete - delete a ring buffer

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID

返回值  :   N/A

函数说明:   rngDelete - delete a ring buffer

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void rngDelete
(
    FAST RING_ID ringId         /* ring buffer to delete */
)
{
    free (ringId->buf);
    free ((char *)ringId);
}

/********************************************************************
函数名称:   rngDelete

函数功能:   make a ring buffer empty

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID

返回值  :   N/A

函数说明:   This routine initializes a specified ring buffer to be empty.
            Any data currently in the buffer will be lost.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void rngFlush
(
    FAST RING_ID ringId         /* ring buffer to initialize */
)
{
    ringId->pToBuf   = 0;
    ringId->pFromBuf = 0;
}

/********************************************************************
函数名称:   rngBufGet

函数功能:   get characters from a ring buffer

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID
buffer          char*           output              pointer to buffer to receive data
maxbytes        size_t          input               maximum number of bytes to get

返回值  :   N/A

函数说明:   This routine initializes a specified ring buffer to be empty.
            Any data currently in the buffer will be lost.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
size_t rngBufGet
(
    FAST RING_ID rngId,         /* ring buffer to get data from      */
    char *buffer,               /* pointer to buffer to receive data */
    size_t maxbytes             /* maximum number of bytes to get    */
)
{
    size_t bytesgot;
    size_t pToBuf = rngId->pToBuf;
    size_t bytes2;
    size_t pRngTmp;

    if (pToBuf >= rngId->pFromBuf)
    {
        /* pToBuf has not wrapped around */

        bytesgot = min (maxbytes, pToBuf - rngId->pFromBuf);
        bcopy (&rngId->buf [rngId->pFromBuf], buffer, bytesgot);
        rngId->pFromBuf += bytesgot;
    }
    else
    {
        /* pToBuf has wrapped around.  Grab chars up to the end of the
         * buffer, then wrap around if we need to. */

        bytesgot = min (maxbytes, rngId->bufSize - rngId->pFromBuf);
        bcopy (&rngId->buf [rngId->pFromBuf], buffer, bytesgot);
        pRngTmp = rngId->pFromBuf + bytesgot;

        /* If pFromBuf is equal to bufSize, we've read the entire buffer,
         * and need to wrap now.  If bytesgot < maxbytes, copy some more chars
         * in now. */

        if (pRngTmp == rngId->bufSize)
        {
            bytes2 = min (maxbytes - bytesgot, pToBuf);
            bcopy (rngId->buf, buffer + bytesgot, bytes2);
            rngId->pFromBuf = bytes2;
            bytesgot += bytes2;
        }
        else
            rngId->pFromBuf = pRngTmp;
    }
    return (bytesgot);
}

/********************************************************************
函数名称:   rngBufPut

函数功能:   get characters from a ring buffer

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID
buffer          char*           intput              buffer to get data from
nbytes          size_t          input               number of bytes to try to put

返回值  :   The number of bytes actually put into the ring buffer;
            it may be less than number requested, even zero,
            if there is insufficient room in the ring buffer at the time of the
            call.

函数说明:   This routine puts bytes from <buffer> into ring buffer <ringId>.  The
            specified number of bytes will be put into the ring, up to the number
            of bytes available in the ring.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
size_t rngBufPut
(
    FAST RING_ID rngId,         /* ring buffer to put data into  */
    char *buffer,               /* buffer to get data from       */
    size_t nbytes               /* number of bytes to try to put */
)
{
    size_t bytesput;
    size_t pFromBuf = rngId->pFromBuf;
    size_t bytes2;
    size_t pRngTmp;

    if (pFromBuf > rngId->pToBuf)
    {
        /* pFromBuf is ahead of pToBuf.  We can fill up to two bytes
         * before it */

        bytesput = min (nbytes, pFromBuf - rngId->pToBuf - 1);
        bcopy (buffer, &rngId->buf [rngId->pToBuf], bytesput);
        rngId->pToBuf += bytesput;
    }
    else if (pFromBuf == 0)
    {
        /* pFromBuf is at the beginning of the buffer.  We can fill till
         * the next-to-last element */

        bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf - 1);
        bcopy (buffer, &rngId->buf [rngId->pToBuf], bytesput);
        rngId->pToBuf += bytesput;
    }
    else
    {
        /* pFromBuf has wrapped around, and its not 0, so we can fill
         * at least to the end of the ring buffer.  Do so, then see if
         * we need to wrap and put more at the beginning of the buffer. */

        bytesput = min (nbytes, rngId->bufSize - rngId->pToBuf);
        bcopy (buffer, &rngId->buf [rngId->pToBuf], bytesput);
        pRngTmp = rngId->pToBuf + bytesput;

        if (pRngTmp == rngId->bufSize)
        {
            /* We need to wrap, and perhaps put some more chars */

            bytes2 = min (nbytes - bytesput, pFromBuf - 1);
            bcopy (buffer + bytesput, rngId->buf, bytes2);
            rngId->pToBuf = bytes2;
            bytesput += bytes2;
        }
        else
            rngId->pToBuf = pRngTmp;
    }
    return (bytesput);
}

/********************************************************************
函数名称:   rngIsEmpty

函数功能:   test if a ring buffer is empty

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID

返回值  :   N/A

函数说明:   test if a ring buffer is empty

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
BOOL rngIsEmpty
(
    RING_ID ringId      /* ring buffer to test */
)
{
    return (ringId->pToBuf == ringId->pFromBuf);
}

/********************************************************************
函数名称:   rngIsEmpty

函数功能:   test if a ring buffer is full (no more room)

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID

返回值  :   N/A

函数说明:   This routine determines if a specified ring buffer is completely full.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
BOOL rngIsFull
(
    FAST RING_ID ringId         /* ring buffer to test */
)
{
    size_t n = ringId->pToBuf - ringId->pFromBuf + 1;

    return ((n == 0) || (n == ringId->bufSize));
}

/********************************************************************
函数名称:   rngFreeBytes

函数功能:   determine the number of free bytes in a ring buffer

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID

返回值  :   N/A

函数说明:   This routine determines the number of bytes currently unused
            in a specified ring buffer.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
size_t rngFreeBytes
(
    FAST RING_ID ringId         /* ring buffer to examine */
)
{
    FAST long n = ringId->pFromBuf - ringId->pToBuf - 1;

    if (n < 0)
        n += ringId->bufSize;

    return (n);
}

/********************************************************************
函数名称:   rngNBytes

函数功能:   determine the number of bytes in a ring buffer

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID

返回值  :   N/A

函数说明:   This routine determines the number of bytes currently in a specified
            ring buffer.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
size_t rngNBytes
(
    FAST RING_ID ringId         /* ring buffer to be enumerated */
)
{
    FAST long n = ringId->pToBuf - ringId->pFromBuf;

    if (n < 0)
        n += ringId->bufSize;

    return (n);
}

/********************************************************************
函数名称:   rngPutAhead

函数功能:   put a byte ahead in a ring buffer without moving ring pointers

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID
byte            char            input               byte to be put in ring
offset          size_t          input               offset beyond next input byte where to put byte

返回值  :   N/A

函数说明:   This routine writes a byte into the ring, but does not move
            the ring buffer pointers.  Thus the byte will not yet be
            available to rngBufGet() calls.The byte is written <offset>
            bytes ahead of the next input location in the ring.  Thus,
            an offset of 0 puts the byte in the same position as would
            RNG_ELEM_PUT would put a byte, except that the input pointer
            is not updated.

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void rngPutAhead
(
    FAST RING_ID ringId,   /* ring buffer to put byte in    */
    char byte,             /* byte to be put in ring        */
    size_t offset          /* offset beyond next input byte where to put byte */
)
{
    FAST size_t n = ringId->pToBuf + offset;

    if (n >= ringId->bufSize)
        n -= ringId->bufSize;

    *(ringId->buf + n) = byte;
}

/********************************************************************
函数名称:   rngMoveAhead

函数功能:   advance a ring pointer by <n> bytes

参数名称        类型            输入/输出           含义
ringId          RING_ID         intput              RING_ID
n               size_t          intput              number of bytes ahead to move input pointer
返回值  :   N/A

函数说明:   This routine advances the ring buffer input pointer by <n>
            bytes.  This makes <n> bytes available in the ring buffer,
            after having been written ahead in the ring buffer with
            rngPutAhead().

修改记录:   2016-10-27  V1.0    王  明  创建
********************************************************************/
void rngMoveAhead
(
    FAST RING_ID ringId,  /* ring buffer to be advanced                  */
    FAST size_t n         /* number of bytes ahead to move input pointer */
)
{
    n += ringId->pToBuf;

    if (n >= ringId->bufSize)
        n -= ringId->bufSize;

    ringId->pToBuf = n;
}
